package com.oraycn.esbasic.utils;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.os.Environment;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by ZN on 2015/10/24.
 */
public class BitmapUtils {

    private static byte R = 0;
    private static byte G = 1;
    private static byte B = 2;

    //    private static RGB yuv2rgb(byte Y, byte U, byte V) {
    //        RGB rgb = new RGB();
    //        int r = (int) ((Y & 0xff) + 1.4075 * ((V & 0xff) - 128));
    //        int g = (int) ((Y & 0xff) - 0.3455 * ((U & 0xff) - 128) - 0.7169 * ((V & 0xff) - 128));
    //        int b = (int) ((Y & 0xff) + 1.779 * ((U & 0xff) - 128));
    //        rgb.r = (byte) (r < 0 ? 0 : r > 255 ? 255 : r);
    //        rgb.g = (byte) (g < 0 ? 0 : g > 255 ? 255 : g);
    //        rgb.b = (byte) (b < 0 ? 0 : b > 255 ? 255 : b);
    //        return rgb;
    //    }
    //
    //    public static byte[] NV21ToRGB(byte[] src, int width, int height) {
    //        int numOfPixel = width * height;
    //        int positionOfV = numOfPixel;
    //        byte[] rgb = new byte[numOfPixel * 3];
    //
    //        for (int i = 0; i < height; i++) {
    //            int startY = i * width;
    //            int step = i / 2 * width;
    //            int startV = positionOfV + step;
    //            for (int j = 0; j < width; j++) {
    //                int Y = startY + j;
    //                int V = startV + j / 2;
    //                int U = V + 1;
    //                int index = Y * 3;
    //                RGB tmp = yuv2rgb(src[Y], src[U], src[V]);
    //                rgb[index + R] = tmp.r;
    //                rgb[index + G] = tmp.g;
    //                rgb[index + B] = tmp.b;
    //            }
    //        }
    //        return rgb;
    //    }

    public static void NV21ToRGB(byte[] nv21, byte[] rgbBuf, int width, int height) {
        final int frameSize = width * height;
        if (rgbBuf == null)
            throw new NullPointerException("buffer 'rgbBuf' is null");
        if (rgbBuf.length < frameSize * 3)
            throw new IllegalArgumentException("buffer 'rgbBuf' size "
                    + rgbBuf.length + " < minimum " + frameSize * 3);

        if (nv21 == null)
            throw new NullPointerException("buffer 'yuv420sp' is null");

        if (nv21.length < frameSize * 3 / 2)
            throw new IllegalArgumentException("buffer 'yuv420sp' size "
                    + nv21.length + " < minimum " + frameSize * 3 / 2);

        int i = 0, y = 0;
        int uvp = 0, u = 0, v = 0;
        int y1192 = 0, r = 0, g = 0, b = 0;

        for (int j = 0, yp = 0; j < height; j++) {
            uvp = frameSize + (j >> 1) * width;
            u = 0;
            v = 0;
            for (i = 0; i < width; i++, yp++) {
                y = (0xff & ((int) nv21[yp])) - 16;
                if (y < 0)
                    y = 0;
                if ((i & 1) == 0) {
                    v = (0xff & nv21[uvp++]) - 128;
                    u = (0xff & nv21[uvp++]) - 128;
                }

                y1192 = 1192 * y;
                r = (y1192 + 1634 * v);
                g = (y1192 - 833 * v - 400 * u);
                b = (y1192 + 2066 * u);

                if (r < 0)
                    r = 0;
                else if (r > 262143)
                    r = 262143;
                if (g < 0)
                    g = 0;
                else if (g > 262143)
                    g = 262143;
                if (b < 0)
                    b = 0;
                else if (b > 262143)
                    b = 262143;

                rgbBuf[yp * 3] = (byte) (r >> 10);
                rgbBuf[yp * 3 + 1] = (byte) (g >> 10);
                rgbBuf[yp * 3 + 2] = (byte) (b >> 10);
            }
        }
    }

    /**
     * byte[] data保存的是纯BGR的数据，而非完整的图片文件数据
     *
     * @param data
     * @param width
     * @param height
     * @return
     */
    public static Bitmap createBGRBitMap(int[] data, int width, int height) {
        Bitmap bmp = null;
        try {
            bmp = Bitmap.createBitmap(data, 0, width, width, height, Bitmap.Config.ARGB_8888);
        } catch (Exception e) {
            // TODO: handle exception
            return null;
        }
        return bmp;
    }


    public static Rect cropSrcmap(int w, int h, int num1, int num2) {
        int retX, retY;
        int nw, nh;
        if (w > h) {
            if (h > w * num2 / num1) {
                nw = w;
                nh = w * num2 / num1;
                retX = 0;
                retY = (h - nh) / 2;
            } else {
                nw = h * num1 / num2;
                nh = h;
                retX = (w - nw) / 2;
                retY = 0;
            }
        } else {
            if (w > h * num2 / num1) {
                nh = h;
                nw = h * num2 / num1;
                retY = 0;
                retX = (w - nw) / 2;
            } else {
                nh = w * num1 / num2;
                nw = w;
                retY = (h - nh) / 2;
                retX = 0;
            }
        }

        return new Rect(retX, retY, nw + retX, nh);
    }

    public static Bitmap createMyBitmap(int[] data, int width, int height) {
        Bitmap bmp = Bitmap.createBitmap(data, width, height, Bitmap.Config.ARGB_8888);
        return bmp;
    }

    public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree) {
        Matrix matrix = new Matrix();
        matrix.postRotate((float) rotateDegree);
        Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
        return rotaBitmap;
    }

    /**
     * 将RGB数组转化为像素数组
	 */
    private static int[] convertByteToColor(byte[] data) {
        int size = data.length;
        if (size == 0) {
            return null;
        }

        // 理论上data的长度应该是3的倍数，这里做个兼容
        int arg = 0;
        if (size % 3 != 0) {
            arg = 1;
        }

        int[] color = new int[size / 3 + arg];
        // int red, green, blue;

        if (arg == 0) {//  正好是3的倍数
            for (int i = 0; i < color.length; ++i) {

                color[i] = (data[i * 3] << 16 & 0x00FF0000) |
                        (data[i * 3 + 1] << 8 & 0x0000FF00) |
                        (data[i * 3 + 2] & 0x000000FF) |
                        0xFF000000;
            }
        } else { // 不是3的倍数
            for (int i = 0; i < color.length - 1; ++i) {
                color[i] = (data[i * 3] << 16 & 0x00FF0000) |
                        (data[i * 3 + 1] << 8 & 0x0000FF00) |
                        (data[i * 3 + 2] & 0x000000FF) |
                        0xFF000000;
            }
            color[color.length - 1] = 0xFF000000;                    // 最后一个像素用黑色填充
        }

        return color;
    }

    /**
     * 将BGR数组转化为像素数组
	 */
    private static int[] convertByteToColorBGR(byte[] data) {
        int size = data.length;
        if (size == 0) {
            return null;
        }

        // 理论上data的长度应该是3的倍数，这里做个兼容
        int arg = 0;
        if (size % 3 != 0) {
            arg = 1;
        }

        int[] color = new int[size / 3 + arg];
        // int red, green, blue;

        if (arg == 0) {//  正好是3的倍数
            for (int i = 0; i < color.length; ++i) {

                color[i] = (data[i * 3 + 2] << 16 & 0x00FF0000) |
                        (data[i * 3 + 1] << 8 & 0x0000FF00) |
                        (data[i * 3] & 0x000000FF) |
                        0xFF000000;
            }
        } else { // 不是3的倍数
            for (int i = 0; i < color.length - 1; ++i) {
                color[i] = (data[i * 3 + 2] << 16 & 0x00FF0000) |
                        (data[i * 3 + 1] << 8 & 0x0000FF00) |
                        (data[i * 3] & 0x000000FF) |
                        0xFF000000;
            }
            color[color.length - 1] = 0xFF000000;                    // 最后一个像素用黑色填充
        }

        return color;
    }

    /**
     * 逆时针的旋转90度的算法
     */
    public static void rgb24Rotate90(byte[] buff, byte[] dest, int width, int height) {
        int n = 0;
        for (int j = width - 1; j >= 0; j--)
            for (int i = 0; i < height; i++) {
                int index = width * 3 * i + j * 3;
                dest[n] = buff[index];
                dest[n + 1] = buff[index + 1];
                dest[n + 2] = buff[index + 2];
                n += 3;
            }
    }

    public static void rgb24Rotate(byte[] buff, byte[] dest, int width, int height) {
        int n = 0;

        // 顺时针的旋转90度的算法
        for (int j = 0; j < width; j++)
            for (int i = height - 1; i >= 0; i--) {
                int index = width * 3 * i + j * 3;
                dest[n + 2] = buff[index];
                dest[n + 1] = buff[index + 1];
                dest[n] = buff[index + 2];
                n += 3;
            }
    }

    /**
     * 左右颠倒
     *
     * @param buff
     * @param dest
     * @param width
     * @param height
     */
    public static void rgbReverse(byte[] buff, byte[] dest, int width, int height) {
        int n = 0;

        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int oldIndex = (i * width + j) * 3;
                int index = (i * width + (width - j - 1)) * 3;
                dest[oldIndex + 2] = buff[index];
                dest[oldIndex + 1] = buff[index + 1];
                dest[oldIndex] = buff[index + 2];
            }
        }
    }

        /**
         * 上下颠倒
         *
         * @param buff
         * @param dest
         * @param width
         * @param height
         */
    public static void rgbupAndDown(byte[] buff, byte[] dest, int width, int height) {
        int n = 0;
        for (int i = height - 1; i > 0; i--) {
            for (int j = 0; j < width; j++) {
                int index = ((i - 1) * width + j) * 3;
                dest[n] = buff[index + 2];
                dest[n + 1] = buff[index + 1];
                dest[n + 2] = buff[index];
                n += 3;
            }
        }
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
                                            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            // Calculate ratios of height and width to requested height and
            // width
            final int heightRatio = Math.round((float) height
                    / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will
            // guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? widthRatio : heightRatio;
        }

        return inSampleSize;
    }

    private static class RGB {
        public byte r, g, b;
    }

}
